package cn.ehcache.abstracts;


import cn.ehcache.CacheManagerProvider;
import cn.ehcache.CacheProvider;
import cn.hutool.core.util.StrUtil;
import lombok.Getter;
import org.ehcache.Cache;
import org.ehcache.CacheManager;
import org.ehcache.StateTransitionException;
import org.ehcache.Status;
import org.ehcache.config.Builder;
import org.ehcache.config.CacheConfiguration;
import org.ehcache.config.Configuration;
import org.ehcache.config.builders.CacheConfigurationBuilder;
import org.ehcache.config.builders.ExpiryPolicyBuilder;
import org.ehcache.config.builders.ResourcePoolsBuilder;
import org.ehcache.expiry.ExpiryPolicy;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.time.Duration;

/**
 * 类简介: 抽象缓存管理器提供程序
 * 建议继承该类来实现缓存,建议每一个类型的缓存都去继承该抽象类,该类将缓存放入到内存当中
 *
 * @Author: ShangGuan
 * @Time: 2024/05/13
 **/
@Getter
public abstract class AbstractCacheManagerProvider<K, V> implements CacheManagerProvider<K, V>, CacheProvider<K, V> {

    private final Class<K> key;
    private final Class<V> value;

    private final CacheManager cacheManager;

    /**
     * 缓存名称--如果为空那么就是当前类className
     */
    private final String cacheName;

    public AbstractCacheManagerProvider(CacheManager cacheManager, String cacheName) {
        Type superClass = getClass().getGenericSuperclass();
        if (superClass instanceof Class<?>) {
            throw new IllegalArgumentException("Missing type parameter.");
        }
        this.key = (Class<K>) ((ParameterizedType) superClass).getActualTypeArguments()[0];
        this.value = (Class<V>) ((ParameterizedType) superClass).getActualTypeArguments()[1];
        if (StrUtil.isNotBlank(cacheName)) {
            this.cacheName = cacheName;
        } else {
            this.cacheName = this.getClass().getName();
        }
        if (cacheManager == null) {
            this.cacheManager = SimpleCacheManager.instants();
        } else {
            this.cacheManager = cacheManager;
        }
    }

    /**
     * 缓存提供程序
     * 使用 new AbstractCacheProvider(){};方式构建
     */

    public AbstractCacheManagerProvider(String cacheName) {
        this(null, cacheName);
    }

    public AbstractCacheManagerProvider() {
        this(null);
    }

    public AbstractCacheManagerProvider(Class<K> key, Class<V> value, String cacheName, CacheManager cacheManager) {
        this.key = key;
        this.value = value;
        this.cacheManager = cacheManager;
        this.cacheName = cacheName;
    }

    public AbstractCacheManagerProvider(Class<K> key, Class<V> value, String cacheName) {
        this.key = key;
        this.value = value;
        this.cacheManager = SimpleCacheManager.instants();
        this.cacheName = cacheName;
    }


    @Override
    public final Cache<K, V> createCache(Duration timeToLive) {
        return createCache(timeToLive, null);
    }

    @Override
    public final Cache<K, V> createCache(Duration timeToLive, Integer capacity) {
        ExpiryPolicy<Object, Object> expiry = ExpiryPolicyBuilder.timeToLiveExpiration(timeToLive);
        ResourcePoolsBuilder resourcePoolsBuilder =
                capacity == null ? ResourcePoolsBuilder.heap(10000) : ResourcePoolsBuilder.heap(capacity);
        CacheConfiguration<K, V> build = CacheConfigurationBuilder
                .newCacheConfigurationBuilder(
                        key, value,
                        resourcePoolsBuilder) // 设置缓存容量
                .withExpiry(expiry) // 设置过期策略
                .build();
        return cacheManager.createCache(cacheName, build);
    }

    @Override
    public Cache<K, V> getCache() {
        return cacheManager.getCache(cacheName, key, value);
    }

    @Override
    public void removeCache(String cacheName) {
        cacheManager.removeCache(cacheName);
    }

    @Override
    public Configuration getRuntimeConfiguration() {
        return cacheManager.getRuntimeConfiguration();
    }

    @Override
    public <K, V> Cache<K, V> createCache(String s, CacheConfiguration<K, V> cacheConfiguration) {
        return cacheManager.createCache(s, cacheConfiguration);
    }

    @Override
    public <K, V> Cache<K, V> createCache(String s, Builder<? extends CacheConfiguration<K, V>> builder) {
        return cacheManager.createCache(s, builder);
    }

    @Override
    public <K, V> Cache<K, V> getCache(String s, Class<K> aClass, Class<V> aClass1) {
        return cacheManager.getCache(s, aClass, aClass1);
    }

    @Override
    public void init() throws StateTransitionException {
        cacheManager.init();
    }

    @Override
    public void close() throws StateTransitionException {
        cacheManager.close();
    }

    @Override
    public Status getStatus() {
        return cacheManager.getStatus();
    }
}
